/*
 *--------------------------------------------------------------------------
 *   File Name:	bits.h
 * 
 * Description:	none
 * 
 * 
 *      Author:	Zhao Yanbai [zhaoyanbai@126.com]
 * 
 *     Version:	1.0
 * Create Date: Wed Mar  4 20:56:29 2009
 * Last Update: Wed Mar  4 20:56:29 2009
 * 
 *--------------------------------------------------------------------------
 */

#ifndef	_BITS_H
#define	_BITS_H

//#define	SET_BIT(bit) (1UL<<bit)
//#define	CLR_BIT(bit) (~(1UL<<bit))
//#define	ISSET_BIT(val,bit) ((val) & SET_BIT(bit))
#define	SET_BIT(val, bit)	(val |= (1UL<<bit))
#define	CLR_BIT(val, bit)	(val &= (~(1UL<<bit)))
#define	XOR_BIT(val, bit)	(btc((unsigned int *)&val, bit), val)
#define	ISSET_BIT(val, bit)	(val & (1UL<<bit))
#define	ISCLR_BIT(val, bit)	(!ISSET_BIT(val, bit))

static inline void btc(unsigned int *v, unsigned int b)
{
	asm ("btc %1,%0":"=m"(*v): "Ir"(b));
}


/*
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
{
	int oldbit;
	asm volatile("btr %2,%1\n\t"
		     "sbb %0,%0"
		     : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");
	return oldbit;
}
*/
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
{
	int oldbit;

	asm volatile("btr %2,%1\n\t"
		     "sbb %0,%0"
		     : "=r" (oldbit), "+m" (*(volatile long *) (addr)) 
		     : "Ir" (nr) : "memory");

	return oldbit;
}
/**
 * test_and_change_bit - Change a bit and return its old value
 * @nr: Bit to change
 * @addr: Address to count from
 *
 * This operation is atomic and cannot be reordered.
 * It also implies a memory barrier.
 */
static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
{
	int oldbit;

	asm volatile("btc %2,%1\n\t"
		     "sbb %0,%0"
		     : "=r" (oldbit), "+m" (*(volatile long *) (addr)) 
		     : "Ir" (nr) : "memory");

	return oldbit;
}

/**
 * change_bit - Toggle a bit in memory
 * @nr: the bit to change
 * @addr: the address to start counting from
 *
 * Unlike change_bit(), this function is non-atomic and may be reordered.
 * If it's called on the same region of memory simultaneously, the effect
 * may be that only one operation succeeds.
 */
static inline void change_bit(int nr, volatile unsigned long *addr)
{
	asm volatile("btc %1,%0": "+m" (*(volatile long *) (addr)) 
				: "Ir" (nr));
}

static inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
{

	return ((1UL << (nr % sizeof(unsigned long))) & 
		(((unsigned long *)addr)[nr / sizeof(unsigned long)]))
		!= 0;
}

static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
{
	int oldbit;

	asm volatile("bt %2,%1\n\t"
		     "sbb %0,%0"
		     : "=r" (oldbit)
		     : "m" (*(unsigned long *)addr), "Ir" (nr));

	return oldbit;
}
#endif //_BITS_H
